package com.scheduling.schedule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.scheduling.order.entity.Order;
import com.scheduling.order.mapper.OrderMapper;
import com.scheduling.schedule.algorithm.ScheduleAlgorithm;
import com.scheduling.schedule.dto.SchedulePlanDTO;
import com.scheduling.schedule.dto.ScheduleRequest;
import com.scheduling.schedule.dto.ScheduleResult;
import com.scheduling.schedule.entity.MachineLoad;
import com.scheduling.schedule.entity.ProductionTask;
import com.scheduling.schedule.entity.ScheduleDetail;
import com.scheduling.schedule.entity.SchedulePlan;
import com.scheduling.schedule.entity.WorkOrder;
import com.scheduling.schedule.enums.ScheduleAlgorithmType;
import com.scheduling.schedule.enums.ScheduleStatus;
import com.scheduling.schedule.mapper.MachineLoadMapper;
import com.scheduling.schedule.mapper.ProductionTaskMapper;
import com.scheduling.schedule.mapper.ScheduleDetailMapper;
import com.scheduling.schedule.mapper.SchedulePlanMapper;
import com.scheduling.schedule.mapper.WorkOrderMapper;
import com.scheduling.schedule.service.MachineLoadService;
import com.scheduling.schedule.service.ScheduleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 排产服务实现类
 *
 * @author 开发团队
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ScheduleServiceImpl implements ScheduleService {

    private final SchedulePlanMapper schedulePlanMapper;
    private final ScheduleDetailMapper scheduleDetailMapper;
    private final ProductionTaskMapper productionTaskMapper;
    private final WorkOrderMapper workOrderMapper;
    private final Map<String, ScheduleAlgorithm> algorithmMap;
    private final MachineLoadMapper machineLoadMapper;
    private final OrderMapper orderMapper;
    private final MachineLoadService machineLoadService;

    @Override
    public ScheduleResult executeSchedule(ScheduleRequest request) {
        log.info("开始执行排产算法，算法类型: {}, 订单数量: {}",
                request.getAlgorithmType(), request.getOrderIds().size());

        try {
            // 1. 参数验证
            validateScheduleRequest(request);

            // 2. 获取排产算法
            ScheduleAlgorithm algorithm = getScheduleAlgorithm(request.getAlgorithmType());

            // 3. 根据订单ID获取订单数据
            List<Order> orders = getOrdersByIds(request.getOrderIds());

            // 4. 确定排产开始时间
            LocalDateTime scheduleStartTime = determineScheduleStartTime(request.getScheduleStartTime());

            // 5. 执行排产算法（订单→工单→任务的完整流程）
            ScheduleResult result = algorithm.schedule(orders, scheduleStartTime);

            log.info("排产算法执行完成，成功: {}, 任务数: {}", result.isSuccess(), result.getTotalTasks());
            return result;

        } catch (Exception e) {
            log.error("排产算法执行失败: {}", e.getMessage(), e);

            ScheduleResult errorResult = new ScheduleResult();
            errorResult.setSuccess(false);
            errorResult.setErrorMessage(e.getMessage());
            errorResult.setAlgorithmType(request.getAlgorithmType());
            return errorResult;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveSchedulePlan(ScheduleResult scheduleResult, ScheduleRequest request) {
        log.info("开始保存排产计划，算法类型: {}", request.getAlgorithmType());

        try {
            // 1. 保存排产计划主记录
            SchedulePlan schedulePlan = createSchedulePlan(scheduleResult, request);
            schedulePlanMapper.insert(schedulePlan);

            // 2. 保存算法生成的工单（必须在生产任务之前保存，因为外键约束）
            if (scheduleResult.getGeneratedWorkOrders() != null) {
                for (WorkOrder workOrder : scheduleResult.getGeneratedWorkOrders()) {
                    workOrderMapper.insert(workOrder);
                    log.debug("保存算法生成的工单: {}", workOrder.getWorkOrderId());
                }
                log.info("保存了 {} 个算法生成的工单", scheduleResult.getGeneratedWorkOrders().size());
            }

            // 3. 保存生产任务
            if (scheduleResult.getProductionTasks() != null) {
                for (ProductionTask task : scheduleResult.getProductionTasks()) {
                    productionTaskMapper.insert(task);
                }
                log.info("保存了 {} 个生产任务", scheduleResult.getProductionTasks().size());

                // 3.5. 更新机器负荷表（在生产任务保存后）
                updateMachineLoadTable(scheduleResult.getProductionTasks());
            }

            // 4. 保存排产详情
            if (scheduleResult.getScheduleDetails() != null) {
                AtomicInteger sequence = new AtomicInteger(1);
                for (ScheduleDetail detail : scheduleResult.getScheduleDetails()) {
                    // 强制设置所有必需字段
                    detail.setPlanId(schedulePlan.getPlanId());
                    detail.setSequenceNo(sequence.getAndIncrement());

                    // 确保所有字段都有值
                    if (detail.getDetailId() == null) {
                        detail.setDetailId("DETAIL_" + System.currentTimeMillis() + "_" + sequence.get());
                    }
                    if (detail.getCreateTime() == null) {
                        detail.setCreateTime(LocalDateTime.now());
                    }

                    log.debug("保存排产详情: detailId={}, planId={}, taskId={}, sequenceNo={}",
                            detail.getDetailId(), detail.getPlanId(), detail.getTaskId(), detail.getSequenceNo());

                    scheduleDetailMapper.insert(detail);
                }
                log.info("保存了 {} 个排产详情", scheduleResult.getScheduleDetails().size());
            }

            log.info("排产计划保存成功，计划ID: {}", schedulePlan.getPlanId());
            return schedulePlan.getPlanId();

        } catch (Exception e) {
            log.error("保存排产计划失败", e);
            throw new RuntimeException("保存排产计划失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean confirmSchedulePlan(String planId) {
        log.info("确认排产计划，计划ID: {}", planId);

        try {
            SchedulePlan schedulePlan = schedulePlanMapper.selectById(planId);
            if (schedulePlan == null) {
                throw new RuntimeException("排产计划不存在: " + planId);
            }

            // 更新排产计划状态
            schedulePlan.setStatus(ScheduleStatus.CONFIRMED.getStatus());
            schedulePlan.setConfirmTime(LocalDateTime.now());
            schedulePlanMapper.updateById(schedulePlan);

            //更新订单状态为已排产
            updateOrderStatus(planId, "生产中");
            // 更新相关工单状态为
            updateWorkOrdersStatus(planId, "生产中");
            //减少原料库存
            updateMaterialInventory(planId);
            //更新机器状态
            updateMachineStatus(planId, "生产中");

            log.info("排产计划确认成功，计划ID: {}", planId);
            return true;

        } catch (Exception e) {
            log.error("确认排产计划失败，计划ID: {}", planId, e);
            return false;
        }
    }

    private void updateMachineStatus(String planId, String status) {
        int updateNum = schedulePlanMapper.updateMachineStatusByPlanId(planId, status);
        log.info("更新原料库存次数: {}", updateNum);
    }

    private void updateMaterialInventory(String planId) {
        //减少原料库存
        int updateNum = schedulePlanMapper.updateInventoryByPlanId(planId);
        log.info("更新原料库存次数: {}", updateNum);
    }

    private void updateOrderStatus(String planId, String status) {
        //更新订单状态为已排产
        int updateOrderNum = schedulePlanMapper.updateOrderStatusByPlanId(planId, status);
        int updateOrderItemNum = schedulePlanMapper.updateOrderItemStatusByPlanId(planId, status);
        log.info("更新订单数目: {}", updateOrderNum);
        log.info("更新订单项数目: {}", updateOrderItemNum);
    }

    @Override
    public List<SchedulePlan> getSchedulePlans() {
        LambdaQueryWrapper<SchedulePlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(SchedulePlan::getCreateTime);
        return schedulePlanMapper.selectList(queryWrapper);
    }

    @Override
    public SchedulePlanDTO getSchedulePlanById(String planId) {
        SchedulePlanDTO dto = new SchedulePlanDTO();

        // 1.查询排产计划主信息
        SchedulePlan plan = schedulePlanMapper.selectById(planId);
        if (plan == null) {
            throw new RuntimeException("排产计划不存在: " + planId);
        }
        dto.setSchedulePlan(plan);

        // 2.查询排产详情
        List<ScheduleDetail> details = scheduleDetailMapper.selectByPlanId(planId);
        dto.setScheduleDetails(details);
        dto.setTotalScheduleDetails(details.size());

        // 3.查询关联的生产任务
        List<String> taskIds = details.stream()
                .map(ScheduleDetail::getTaskId)
                .distinct()
                .collect(Collectors.toList());
        List<ProductionTask> tasks = productionTaskMapper.selectBatchIds(taskIds);
        dto.setProductionTasks(tasks);
        dto.setTotalTasks(tasks.size());

        // 4.查询关联的工单
        List<String> workOrderIds = tasks.stream()
                .map(ProductionTask::getWorkOrderId)
                .distinct()
                .collect(Collectors.toList());
        List<WorkOrder> workOrders = workOrderMapper.selectBatchIds(workOrderIds);
        dto.setWorkOrders(workOrders);
        dto.setTotalWorkOrders(workOrders.size());

        // 5.统计机器数量
        long machineCount = details.stream()
                .map(ScheduleDetail::getMachineId)
                .distinct()
                .count();
        dto.setTotalMachines((int) machineCount);

        return dto;
    }

    @Override
    public List<WorkOrder> getPendingWorkOrders() {
        return workOrderMapper.selectPendingScheduleOrders();
    }

    @Override
    public List<String> getSupportedAlgorithmTypes() {
        return Arrays.stream(ScheduleAlgorithmType.values())
                .map(ScheduleAlgorithmType::getCode)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteSchedulePlan(String planId) {
        log.info("删除排产计划，计划ID: {}", planId);

        try {
            // 获取任务ID集合
            List<String> taskIds = scheduleDetailMapper.selectList(new LambdaQueryWrapper<ScheduleDetail>()
                            .select(ScheduleDetail::getTaskId)
                            .eq(ScheduleDetail::getPlanId, planId))
                    .stream().map(ScheduleDetail::getTaskId).collect(Collectors.toList());

            if (!taskIds.isEmpty()) {
                // 删除机器负荷记录
                machineLoadMapper.deleteBatchByTaskIds(taskIds);
                log.info("删除机器负荷记录，任务数量: {}", taskIds.size());
                // 获取关联工单ID
                List<String> workOrderIds = productionTaskMapper
                        .selectList(new LambdaQueryWrapper<ProductionTask>()
                                .select(ProductionTask::getWorkOrderId)
                                .in(ProductionTask::getTaskId, taskIds))
                        .stream().map(ProductionTask::getWorkOrderId).distinct().collect(Collectors.toList());

                // 删除工单
                if (!workOrderIds.isEmpty()) {
                    workOrderMapper.delete(new LambdaQueryWrapper<WorkOrder>()
                            .in(WorkOrder::getWorkOrderId, workOrderIds));
                }

                // 删除生产任务
                productionTaskMapper.delete(new LambdaQueryWrapper<ProductionTask>()
                        .in(ProductionTask::getTaskId, taskIds));
            }

            // 删除排产详情
            scheduleDetailMapper.delete(new LambdaQueryWrapper<ScheduleDetail>()
                    .eq(ScheduleDetail::getPlanId, planId));

            // 删除排产计划
            schedulePlanMapper.deleteById(planId);

            log.info("排产计划删除成功，计划ID: {}", planId);
            return true;

        } catch (Exception e) {
            log.error("删除排产计划失败，计划ID: {}", planId, e);
            return false;

        }
    }

    /**
     * 验证排产请求参数
     */
    private void validateScheduleRequest(ScheduleRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("排产请求不能为空");
        }

        if (request.getOrderIds() == null || request.getOrderIds().isEmpty()) {
            throw new IllegalArgumentException("订单列表不能为空");
        }

        if (!StringUtils.hasText(request.getAlgorithmType())) {
            throw new IllegalArgumentException("算法类型不能为空");
        }
    }

    /**
     * 获取排产算法实例
     */
    private ScheduleAlgorithm getScheduleAlgorithm(String algorithmType) {
        ScheduleAlgorithm algorithm = algorithmMap.get(algorithmType);
        if (algorithm == null) {
            throw new IllegalArgumentException("不支持的算法类型: " + algorithmType);
        }
        return algorithm;
    }

    /**
     * 确定排产开始时间
     */
    private LocalDateTime determineScheduleStartTime(String scheduleStartTimeStr) {
        if (StringUtils.hasText(scheduleStartTimeStr)) {
            try {
                return LocalDateTime.parse(scheduleStartTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            } catch (Exception e) {
                log.warn("排产开始时间格式错误，使用当前时间: {}", scheduleStartTimeStr);
            }
        }
        return LocalDateTime.now();
    }

    /**
     * 创建排产计划
     */
    private SchedulePlan createSchedulePlan(ScheduleResult scheduleResult, ScheduleRequest request) {
        SchedulePlan schedulePlan = new SchedulePlan();
        schedulePlan.setPlanId("PLAN_" + System.currentTimeMillis());
        schedulePlan.setPlanName(request.getPlanName());
        schedulePlan.setAlgorithmType(request.getAlgorithmType());
        schedulePlan.setStatus(ScheduleStatus.DRAFT.getStatus());
        schedulePlan.setPlanStartTime(scheduleResult.getScheduleStartTime());
        schedulePlan.setPlanEndTime(scheduleResult.getScheduleEndTime());
        schedulePlan.setTotalUtilization(scheduleResult.getTotalUtilization());
        schedulePlan.setCreateTime(LocalDateTime.now());
        schedulePlan.setCreatedBy(request.getCreatedBy());
        return schedulePlan;
    }

    /**
     * 更新机器负荷表
     */
    private void updateMachineLoadTable(List<ProductionTask> productionTasks) {
        if (productionTasks == null || productionTasks.isEmpty()) {
            return;
        }

        log.debug("更新机器负荷表，任务数量: {}", productionTasks.size());

        try {
            List<MachineLoad> machineLoads = new ArrayList<>();

            for (ProductionTask task : productionTasks) {
                MachineLoad load = new MachineLoad();
                load.setLoadId("LOAD_" + task.getTaskId());
                load.setMachineId(task.getMachineId());
                load.setTaskId(task.getTaskId());
                load.setStartTime(task.getPlanStartTime());
                load.setEndTime(task.getPlanEndTime());
                load.setStatus("计划");
                load.setCreateTime(LocalDateTime.now());

                machineLoads.add(load);
            }

            // 批量插入机器负荷记录
            machineLoadService.batchAddMachineLoads(machineLoads);
            log.info("机器负荷表更新完成，新增 {} 条记录", machineLoads.size());

        } catch (Exception e) {
            log.error("更新机器负荷表失败", e);
            // 不影响排产计划保存，继续执行
        }
    }

    /**
     * 更新工单状态
     */
    private void updateWorkOrdersStatus(String planId, String status) {
        try {
            // 根据排产计划ID查询相关工单并更新状态
            int updatedNum = schedulePlanMapper.updateWorkOrdersByPlanId(planId, status);
            log.info("更新工单状态次数: {}", updatedNum);
        } catch (Exception e) {
            log.error("更新工单状态失败", e);
        }
    }

    /**
     * 根据订单ID获取订单列表
     */
    private List<Order> getOrdersByIds(List<String> orderIds) {
        return orderMapper.selectBatchIds(orderIds);
    }


}